home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / comm / maxshell.lha / MAXShell.c < prev    next >
Text File  |  1995-08-28  |  32KB  |  1,100 lines

  1. /*
  2.    MAXShell v1.0 - A door for running CLI based programs under M A X's BBS
  3.    ~~~~~~~~~~~~~
  4.    Based on TrShell, by Timothy Aston. Max's adaption by MPS '95!
  5.  
  6.    At last! Now Max's sysops can access a FULL remote CLI and access the
  7.    huge range of CLI based doors available, such as Hack & Slash, Global
  8.    War 2, and Contris!
  9.  
  10.    This door is pretty much a conversion of the original TAShell for
  11.    TransAmiga BBS, by Timothy Aston (Which used much of the remote CLI
  12.    code from the FIFO distribution), to a Max's compatible door. Extra
  13.    Max's specific functionality has also been added.
  14.  
  15.    To run this door, you will need Matthew Dillon's 'fifo.library' and
  16.    'fifo-handler' installed. Just copy the included 'fifo.library' to
  17.    libs: and 'fifo-handler' to l:, then add 'run >nil: <nil: l:fifo-handler'
  18.    to your user-startup.
  19.  
  20.    Run like any other door (Function 34), and use the following arguments:
  21.  
  22. Usage: MAXShell [<startup-script>] [-c] [-d] [-e] [-f]
  23. ~~~~~~                                   [-s<substitution char>] [-t]
  24.  
  25.    Where: <startup-script> is an optional shell startup script. Use this for
  26.           running games, etc. An example startup script could be:
  27.  
  28.    -----------------------------CUT HERE-----------------------------
  29.    cd doors:globalwar
  30.    globalwar %f ACCESS %l PAGELENGTH %p TIMELEFT %k
  31.    endcli
  32.    -----------------------------CUT HERE-----------------------------
  33.  
  34.           Max's autoinserts can be used in the script for supplying needed
  35.           parameters to shell programs. (For example, the above will supply
  36.           the user name to Global War, as needed).
  37.  
  38.           Note the ENDCLI - This is very important, or users will exit to
  39.           the shell after quitting Global War!
  40.  
  41.           Also note that all scripts must be in BBS:MAXSHELL/, and you
  42.           obviously don't supply the path for this reason. The reason I
  43.           did this was Max's Filename/Name/Dest/Path firld doesn't have
  44.           much room, so this will save characters!
  45.  
  46.           If a startup script filename isn't supplied, MAXShell will just
  47.           give a shell...
  48.  
  49.           -c is a switch to filter out ^C's from the user. Same goes for
  50.              the -d, -e and -f.
  51.  
  52.           You should always have -c and -d enabled, or users can break out
  53.           of the startup script if they're quick enough, and enter CLI!
  54.  
  55.           -s<substitution char> is a switch to enable an additional
  56.           conversion to the user name (%f). The supplied character will
  57.           replace spaces in the user name. This prevents problems with
  58.           command line parsing and spaces in certain programs. I suppose
  59.           you could have used "%f" instead of %f in the script, but it's
  60.           there if you want the feature!
  61.  
  62.           -t is a switch to enable an additional conversion to the user's
  63.           remaining time (%k). The time value will me made to be 5 minutes
  64.           lower. This will allow the CLI based program to exit (Based on
  65.           this time limit) before the BBS will hang up, avoiding problems.
  66.           Of course, this is only useful if the program supports time limits
  67.           in the first place!
  68.  
  69.    (The usage is also shown when MAXShell isn't run as a door, ie. run from
  70.     the CLI).
  71.  
  72. Examples on BBS use of MAXShell:
  73.  
  74. Global War 2: (Assuning above example gw-startup is in DOORS:MAXSHELL/)
  75. Key:  Function:  Extra:  Lo acc:  Hi acc:
  76.  G       34        0       10      10000  
  77.                                           Filename/Name/Dest/Path:
  78.                              DOORS:MAXSHELL/MAXSHELL GW-STARTUP -c -d -s_ -t
  79. Standard CLI:
  80. Key:  Function:  Extra:  Lo acc:  Hi acc:  Filename/Name/Dest/Path:
  81.  !       34        0      10000    10000   DOORS:MAXSHELL/MAXSHELL
  82.  
  83. Notes:     * Make sure you have a standard AmigaDOS shell (I had ZShell
  84. ~~~~~~       in my shell-startup, but will not work with FIFO: as far as
  85.              I could see (In other words, the computer came up with some
  86.              alert, and after I removed 'zsh' from my shell-startup, it
  87.              didn't happen again!)
  88.  
  89.            * Yep, that bug mentioned below does occur in my conversion,
  90.              and, yep, you guessed it, I haven't got the faintest clue
  91.              on why it occurs. The solution is to use a different FIFO
  92.              every time by creating the FIFO name via something like
  93.              time() to make it unique every time a new one is opened!
  94.              This is what I did in converting, and what was originally
  95.              done in the TA scripts that invoked TaShell...
  96.  
  97.            * If a user drops carrier, the program simply sends a ^C to
  98.              the FIFO shell, and exits. This is not always sufficient to
  99.              stop the running shell program. MAXShell will return
  100.              correctly, but the shell process will still be left running.
  101.              This caused complications with the temporary shell-startup
  102.              script I use (With the converted Max's auto-inserts), as it
  103.              will still be in use (By the non-exiting shell), and thus
  104.              can't be removed or changed (Which I needed to do: when
  105.              another user accesses the door, the converted script must
  106.              reflect the new username). A similar workaround was used as
  107.              above to make a unique temporary filename every time. Don't
  108.              worry about about RAM: filling up though, the problem only
  109.              occurs when someone hangs up, or you twit the user. (And even
  110.              then, only in certain cases). One 'locked-out' file occurs
  111.              for each lost-carrier/twit. (Again, only in certain cases).
  112.              This problem exists in the original TaShell also... If anyone
  113.              knows a better way of handling this I'd like to know!
  114.  
  115.            * Max's special conversion characters (@, |, %) are not
  116.              supported at this time - They were causing many problems,
  117.              so they are printed verbatim. If you want to have support
  118.              them, you can always have a go at modifying this source
  119.              code! % should be reasonably easy to get working
  120.              properly. The only precaution is to make sure that the
  121.              program handles the %<char> across a 'split' between
  122.              blocks of output to the Max's screen... This has been
  123.              implemented for escape codes already.
  124.  
  125.            * Another wierd bug: The CLI process number below MAXShell's
  126.              CLI will be suspended until MAXShell's CLI finishes. God
  127.              knows why, it doesn't seem to harm anything, so I can't be
  128.              bothered figuring this one out! Of course, as above, you
  129.              could always try...
  130.  
  131.            * Finally, the user's PAUSE flag is set to OFF during the
  132.              duration of the door (To stop games like Hack & Slash having
  133.              annoying 'Press Return...' prompts every screenfull of text),
  134.              and returned to the user's original setting before exiting to
  135.              the BBS. The PAUSE flag will stay OFF, if the user hangs up or
  136.              is twitted.
  137.  
  138. Contact:   For whatever reason, contact me via e-mail: mp@deakin.edu.au, or
  139. ~~~~~~~~   call my BBS (See BBS advertisement below).
  140.  
  141. Finally:   This program is hereby FREEWARE! You need not pay for it, as
  142. ~~~~~~~~   it's just something I hacked up to add a much needed feature
  143.            to Max's BBS! Just be sure to distribute the files/archive as
  144.            is.
  145.  
  146.            I'm curious why someone hasn't done this door for Max's BBS
  147.            before, as it was a pretty straightforward task even for me,
  148.            (Well, I DID have the TAShell source, I suppose...) and I'm
  149.            not what you'd call the best coder in the world, or the most
  150.            knowledgable Max's guy around! Which reminds me, I must thank
  151.            Greg Fitch for putting me on the right track about obtaining
  152.            Max's user values. Call his BBS: Xyonics on (07)808-4806.
  153.  
  154.            I'm also (As you might have guessed!) distributing source as
  155.            well. I hope I start a trend in doing this, as I found it
  156.            difficult to find C source concerning Max's BBS, so would like
  157.            to pass on the knowledge I gained in doing this door. All I
  158.            ask is to credit me if you change the code, etc. and perhaps
  159.            a bit of extra access on your BBS and/or perhaps a free
  160.            registration of a shareware program you wrote.
  161.  
  162. Have fun with MAXShell!
  163.  
  164. Catch ya later,
  165. MPS!
  166.  
  167. */
  168.  
  169. /* Here is the original TrShell.c introduction:
  170.  
  171.  TrShell, by Timothy Aston
  172.  
  173.    This is put in the public domain as a simple example of how to use
  174.    transamiga.library with TransAmiga.  This was written with DICE but
  175.    should easily be modified to other compilers.  You should note however,
  176.    that DICE opens most libraries automatically (including fifo.library). 
  177.    SAS users will probably have to generate #pragmas for
  178.    transamiga.library and fifo.library.  fifo.h is included with the FIFO
  179.    distribution.
  180.  
  181.    BTW: Note that there does seem to be a persistent bug in this, it
  182.    doesn't fully release the FIFO, any attempt to restart it with an
  183.    already used FIFO name causes NewShell to hang.  If you can figure out
  184.    why this is, I'd really like to know.
  185. */
  186.  
  187. const char version[]="\0$VER: MAXShell 1.0 ("__DATE__")\0";
  188.  
  189. #include <clib/exec_protos.h>
  190. #include <exec/exec.h>
  191. #include <exec/types.h>
  192. #include <exec/memory.h>
  193. #include <exec/ports.h>
  194. #include <exec/libraries.h>
  195. #include <fcntl.h>
  196. #include <libraries/dos.h>
  197. #include <stdio.h>
  198. #include <stdlib.h>
  199. #include <string.h>
  200. #include "fifo.h"
  201. #include "fifopr.h"
  202. #include <proto/exec.h>
  203. #include <proto/dos.h>
  204. #include <time.h>
  205.  
  206. #define ESC 27
  207. #define FF 12
  208.  
  209. char StrOut[255]; /* Output String! */
  210.  
  211. struct Library *FifoBase=NULL;
  212. struct MsgPort *fifoport;
  213. void *fifoR=NULL, *fifoW=NULL;
  214. struct Message rmsg,wmsg;
  215.  
  216. char fifoname[30]="12345678901234567890123456789"; /* Name of FIFO */
  217. char commandline[80]="NewShell FIFO:";
  218.                       /* Command line for opening a FIFO: redirected CLI */
  219. char newfile[30]="";
  220.                       /* Filename for autoinsert-converted shell-startup */
  221. char newchar=' ';     /* Character used to replace spaces in user name */
  222. char charbuf[100],txt[255];
  223. char *fifoslav,*fifomast;
  224. BOOL quit=FALSE;
  225. BOOL readpending=FALSE, writepending=FALSE;
  226. LONG n;
  227.  
  228. BOOL filterc=FALSE, filterd=FALSE, filtere=FALSE, filterf=FALSE, lesstime=FALSE;
  229.  
  230. void setup_fifo(void);
  231. void shell_loop(void);
  232. void Out(char *);
  233. int InChar(void);
  234. void SendBreak(char);
  235. void check_fifo(void);
  236. void OutLen(char * , ULONG);
  237. void convert_lf(char * , char * , LONG);
  238. void show_usage(void);
  239. void close_all(void);
  240.  
  241. long getuserint(int);
  242. void checkkey(char *);
  243. void GetAutoInsert(char, char *);
  244.  
  245. void end(void);
  246. void getsvar(int, char *);
  247. void sendmessage(char[], int);
  248. void hotkey(char[], char *);
  249. void prompt(char[], char *, int);
  250. void showfile(char[]);
  251. void domenu(int, int, char *);
  252. void changeuserint(int, long);
  253.  
  254. struct DoorMsg {
  255.     struct Message Door_Msg;
  256.     short command;
  257.     short data;
  258.     char string[80];
  259.     short carrier;
  260.     };
  261.  
  262. struct DoorMsg *doormsg, *garbage;
  263. struct MsgPort *MyPort, *replyport;
  264.  
  265. struct Task *mytask; /* Pointer to this task so we can name it */
  266.  
  267. int err;
  268.  
  269. char linebuf[3000]=""; /* Line buffer */
  270.  
  271. time_t timeval;   /* So we can get the time (For a different FIFO  name    */
  272. time_t *timeptr; /* every time the door is run (Avoiding the closing bug) */
  273.  
  274. FILE *ifp, *ofp, *fopen();
  275.  
  276. /*
  277.  * end() -  Notifies Paragon that we are done and ready to continue with
  278.  *        the BBS.  ALWAYS use this to exit from your program, or
  279.  *        the BBS will go to never-never land.
  280.  */
  281.  
  282. void end(void)
  283. {
  284.     doormsg->command = 20;
  285.     PutMsg(MyPort,(struct Message *)doormsg);
  286.     (void)WaitPort(replyport);
  287.     (void)GetMsg(replyport);
  288.     FreeMem(doormsg,(long)sizeof(*doormsg));
  289.     DeletePort(replyport);
  290.     exit(0);
  291. }
  292.  
  293. /*
  294.  * getsvar(typ,mstring) - Gets certain string variables from Paragon.
  295.  * "mstring" is a pointer to a string to dump the string into.  "typ" tells
  296.  * it what you want: 1=Name, 2=Password, 3=Address, 4=City, 5=State
  297.  * 6=Postal code, 7=Door pathname, 8=Default BBS pathname.
  298.  */
  299.  
  300. /* Extra Max's values:                 9: Date
  301.                                        10: Time
  302.                                        100: Phone number
  303.                                        101: Computer type
  304.                                        102: Comment (as defined by Sysop) */
  305.  
  306. void getsvar(typ,mstring)
  307. int typ;
  308. char *mstring;
  309. {
  310.     doormsg->data = typ;
  311.     doormsg->command = 14;
  312.     PutMsg(MyPort,(struct Message *)doormsg);
  313.     (void)WaitPort(replyport);
  314.     strcpy(mstring,doormsg->string);
  315.     (void)GetMsg(replyport);
  316. }
  317.  
  318. /*
  319.  * sendmessage(mstring,nl) - Sends a message to the local window and to
  320.  * the modem (if applicable).  "mstring" is the output string you want to
  321.  * send, "nl" is an integer which is 1 if you want it to send the
  322.  * c/r+l/f combination, or 0 if not.
  323.  */
  324.  
  325. void
  326. sendmessage(mstring,nl)
  327. char mstring[];
  328. int nl;
  329. {
  330. char newstr[100];
  331. int i, ii=0;
  332.     doormsg->data = nl;
  333.     doormsg->command = 1;
  334.  
  335. /* Strip out some unwanted escape codes. (What the hell do the <ESC>[ p
  336.    escape codes do anyway? This sloppy code just makes things like Contris
  337.    look better rather than having strange [ p's showing up in places) */
  338.  
  339. for(i=0; i<strlen(mstring); i++)
  340. {
  341.         newstr[ii]=mstring[i];
  342.         if(newstr[ii]=='\033' && mstring[i+1]=='[' && mstring[i+3]==' '
  343.                                    && mstring[i+4]=='p')
  344.         {
  345.                 ii--;
  346.                 i+=4;
  347.         }
  348.         else if(newstr[ii]=='\033' && mstring[i+1]=='[' && mstring[i+2]==' '
  349.                                    && mstring[i+3]=='p')
  350.         {
  351.                 ii--;
  352.                 i+=3;
  353.         }
  354.         else if(newstr[ii]=='\033' && mstring[i+1]=='\033' && mstring[i+2]=='['
  355.                                    && mstring[i+3]==' ' && mstring[i+4]=='p')
  356.         {
  357.                 ii--;
  358.                 i+=4;
  359.         }
  360.         else if(newstr[ii]=='\033' && mstring[i+1]=='\033' && mstring[i+2]=='['
  361.                                    && mstring[i+4]==' ' && mstring[i+5]=='p')
  362.         {
  363.                 ii--;
  364.                 i+=5;
  365.         }
  366.         ii++;
  367. }
  368.         newstr[ii]='\0';
  369.     strcpy(doormsg->string,newstr);
  370.         PutMsg(MyPort,(struct Message *)doormsg);
  371.     (void)WaitPort(replyport);
  372.     (void)GetMsg(replyport);
  373. }
  374.  
  375. /*
  376.  * hotkey(mstring,ostring) - outputs the string "mstring" and waits
  377.  * for one key which it will place in element [0] of "ostring".
  378.  * "mstring" may be a null string, in which case it will only wait for
  379.  * the key, and not output any prompt.
  380.  */
  381.  
  382. void
  383. hotkey(mstring,ostring)
  384. char mstring[];
  385. char *ostring;
  386. {
  387.     strcpy(doormsg->string,mstring);
  388.     doormsg->command = 8;
  389.     PutMsg(MyPort,(struct Message *)doormsg);
  390.     (void)WaitPort(replyport);
  391.     (void)GetMsg(replyport);
  392.     strcpy(ostring,doormsg->string);
  393. }
  394.  
  395. /*
  396.  * prompt(mstring,ostring,len) - outputs the string "mstring" and inputs
  397.  * a string which is placed in ostring.  'len' is the maximum number of
  398.  * characters which will be accepted.
  399.  */
  400.  
  401. void
  402. prompt(mstring,ostring,len)
  403. char mstring[];
  404. char *ostring;
  405. int len;
  406. {
  407.     strcpy(doormsg->string,mstring);
  408.     doormsg->data=len;
  409.     doormsg->command = 6;
  410.     PutMsg(MyPort,(struct Message *)doormsg);
  411.     (void)WaitPort(replyport);
  412.     (void)GetMsg(replyport);
  413.     strcpy(ostring,doormsg->string);
  414. }
  415.  
  416.  
  417. /* showfile(mstring) shows the text file which mstring is the path to.
  418.    It handles ^C aborting, and ^S/^Q pausing. */
  419.  
  420. void
  421. showfile(mstring)
  422. char mstring[];
  423. {
  424.     strcpy(doormsg->string,mstring);
  425.     doormsg->command = 10;
  426.     PutMsg(MyPort,(struct Message *)doormsg);
  427.     (void)WaitPort(replyport);
  428.     (void)GetMsg(replyport);
  429. }
  430.  
  431. /****************************************************
  432.     These two functions were added by
  433.          SWhite. MAX's BBS only!
  434. ****************************************************/
  435. /* enter a menu function to execute 1-33 */
  436. void
  437. domenu(menu,extra,filename)
  438. int menu,extra;
  439. char *filename;
  440.  {
  441.     strcpy(doormsg->string,filename);
  442.     doormsg->command = menu+100;
  443.     doormsg->data     = extra;
  444.     PutMsg(MyPort,(struct Message *)doormsg);
  445.     (void)WaitPort(replyport);
  446.     (void)GetMsg(replyport);
  447. }
  448.  
  449. /* Change user information 1-15:
  450.  
  451.    0      NextEventMinutes
  452.    1       UserTimeRemaining
  453.    2      AccessLevel
  454.    3      TimeLeft
  455.    4      DL Ratio
  456.    5      Last Message Read
  457.    6      PageLength
  458.    7      NumCalls
  459.    8      UserMessages #
  460.    9      UserUpped Files
  461.    10     UserDownedFiles
  462.    11     LastDayOn
  463.    12     Last Minute On
  464.    13     UserConfig Flags                ;Lower 2 Bytes
  465.  
  466.                   Flags, bits: 0-Rd, 1-Wr, 2-Up, 3-Dn, 4-Bltn, 5-ANSI
  467.                                6-FSE, 7-Pause, 8-Cls, 9-Lck, 10-Get file
  468.                                description, 11-Junk mail, 12-Allow File
  469.                                Attaches
  470.    14     UserTimeBank
  471.    15     XFer Protocol
  472.    16     MaxTimeBank
  473. */
  474.  
  475. void
  476. changeuserint(number,val)
  477. int number;
  478. long val;
  479.  {
  480.     long *ptr;
  481.  
  482.     ptr = (long *)&doormsg->string;    /* We need a long value not a ptr */
  483.     *ptr = val;
  484.     
  485.     doormsg->command = 200;
  486.     doormsg->data    = number;
  487.     PutMsg(MyPort,(struct Message *)doormsg);
  488.     (void)WaitPort(replyport);
  489.     (void)GetMsg(replyport);
  490.  }
  491.  
  492. /* Get a piece of the user's integer information:
  493.  
  494.                 1:  Access Level
  495.                 2:  Expert mode?  (Paragon)
  496.                 3:  Net Credits?  (paragon)
  497.                 4:  Number of calls
  498.                 5:  Calls to system
  499.                 6:  Graphics mode
  500.                 7:  Minutes remaining
  501.                 8:  Screen columns
  502.                 9:  Screen rows
  503.               100:  Daily time limit
  504.               101:  File ratio
  505.               102:  Last message read (Updated when user logs off)
  506.               103:  Messages posted
  507.               104:  Files uploaded
  508.               105:  Files downloaded
  509.               106:  ?
  510.               107:  ?
  511.               108:  Flags (Binary bits)
  512.          +--------+------------+--------+---------------+ 
  513.          |  FLAG  |  VALUE     |  FLAG  |  VALUE        |  Examples
  514.          +--------+------------+--------+---------------+  ~~~~~~~~
  515.          |  Read  |  1 (2^0)   |  Pause |  128  (2^7)   | ALL ON      : 8191 
  516.          |  Write |  2 (2^1)   |  CLS   |  256  (2^8)   | ALL OFF     : 0
  517.          |  Upld  |  4 (2^2)   |  Lock  |  512  (2^9)   | Upld + Dnld : 12  
  518.          |  Dnld  |  8 (2^3)   |  GFD   |  1024 (2^10)  | ANSI + FSE  : 96
  519.          |  Bltn  | 16 (2^4)   |  Junk  |  2048 (2^11)  |
  520.          |  ANSI  | 32 (2^5)   |  AFA   |  4096 (2^13)  |
  521.          |  FSE   | 64 (2^6)   |        |               |
  522.          +--------+------------+--------+---------------+
  523.               109:  Amount in time bank
  524.               110:  Protocol
  525.               111:  Max time bank
  526. */
  527.  
  528. long getuserint(int val)
  529. {
  530.    doormsg->command=13;
  531.    doormsg->data=val;
  532.    PutMsg(MyPort,(struct Message *)doormsg);
  533.    (void)WaitPort(replyport);
  534.    (void)GetMsg(replyport);
  535.    return(doormsg->data);
  536. }
  537.  
  538. /* Check for a key, without any waiting or prompting */
  539.  
  540. void CheckKey(char *ostring)
  541. {
  542.    doormsg->command = 201;
  543.    PutMsg(MyPort,(struct Message *)doormsg);
  544.    (void)WaitPort(replyport);
  545.    (void)GetMsg(replyport);
  546.    strcpy(ostring,doormsg->string);
  547. }
  548.  
  549. /* Return Max's auto insert (And also replace spaces with defined
  550.    substitution character, in the full user name, if applicable) */
  551.  
  552. void GetAutoInsert(char istring, char *ostring)
  553. {
  554. int i;
  555.    doormsg->command = 203;
  556.    doormsg->data = istring;
  557.    PutMsg(MyPort,(struct Message *)doormsg);
  558.    (void)WaitPort(replyport);
  559.    (void)GetMsg(replyport);
  560.    strcpy(ostring,doormsg->string);
  561.    if(istring=='f')
  562.    {
  563.       for(i=0;i<strlen(ostring);i++)
  564.       {
  565.          if(ostring[i]==' ')
  566.          {
  567.             ostring[i]=newchar;
  568.          }
  569.       }
  570.    }
  571.    if(istring=='k' && lesstime==TRUE)
  572.    {
  573.       i=atoi(ostring);
  574.       i-=5;
  575.       if(i<0) i=0;
  576.       sprintf(ostring, "%d", i);
  577.    }
  578. }
  579.  
  580. /* Setup FIFO, requires Dillon's fifo.library.
  581.  */
  582. void setup_fifo()
  583. {
  584.     fifoslav = (char *) malloc(strlen(fifoname) + 16);
  585.     fifomast = (char *) malloc(strlen(fifoname) + 16);
  586.     sprintf(fifomast, "%s_m", fifoname);
  587.     sprintf(fifoslav, "%s_s", fifoname);
  588.     
  589.     fifoport=CreatePort(NULL,0L);
  590.  
  591.     fifoW = OpenFifo(fifomast, 2048, FIFOF_WRITE|FIFOF_NORMAL|FIFOF_NBIO);
  592.     if (fifoW == NULL)
  593.     {
  594.         printf("ERROR: Unable to open fifo %s\n", fifomast);
  595.  
  596. /* Temporary: I'll have to change this... */
  597.  
  598.         exit(10);
  599.     }
  600.     fifoR = OpenFifo(fifoslav, 2048, FIFOF_READ|FIFOF_NORMAL|FIFOF_NBIO);
  601.     if (fifoR == NULL)
  602.     {
  603.         printf("ERROR: Unable to open fifo %s\n", fifoslav);
  604.  
  605. /* Temporary: I'll have to change this... */
  606.  
  607.         exit(10);
  608.     }
  609.  
  610.     rmsg.mn_ReplyPort = fifoport;
  611.     wmsg.mn_ReplyPort = fifoport;
  612. }
  613.  
  614. /* The main shell loop.
  615.  */
  616. void shell_loop(void)
  617. {
  618.     char c;
  619.     char outstr[100];
  620.  
  621.         sprintf(outstr, "\r\nMAXShell v1.0\n\r\n");
  622.     Out(outstr);
  623.     
  624.     RequestFifo(fifoR,&rmsg,FREQ_RPEND);
  625.     readpending=TRUE;
  626.     
  627.     while (quit==FALSE)
  628.     {       
  629.         c=InChar();
  630.         switch ( (int) c)
  631.         {
  632.             case 3:
  633.                                 if(filterc==FALSE) SendBreak('C');
  634.                 break;
  635.             case 4:
  636.                 if(filterd==FALSE) SendBreak('D');
  637.                 break;
  638.             case 5:
  639.                 if(filtere==FALSE) SendBreak('E');
  640.                 break;
  641.             case 6:
  642.                 if(filterf==FALSE) SendBreak('F');
  643.                 break;
  644.             default:
  645.                 n=WriteFifo(fifoW,&c,1);
  646.                 if (n<1)
  647.                 {
  648.                     if (writepending==FALSE)
  649.                     {
  650.                         RequestFifo(fifoW,&wmsg,FREQ_RPEND);
  651.                         writepending=TRUE;
  652.                     }
  653.                 }
  654.                 break;
  655.         }
  656.     };
  657.         sendmessage(charbuf, 0);  /* Flush the character buffer */
  658.     n=WriteFifo(fifoW,"\r",1);
  659.     if (n<1)
  660.     {
  661.         if (writepending==FALSE)
  662.         {
  663.             RequestFifo(fifoW,&wmsg,FREQ_RPEND);
  664.             writepending=TRUE;
  665.         }
  666.     }
  667. }
  668.  
  669.  
  670. /* Get a character, complete with carrier checks and rudimentry idle timer
  671.  * checking.  Serial routines are smart enough to know whether or not 
  672.  * serial I/O should place or not, so there's no need to check if this is
  673.  * a local logon or anything like that.
  674.  */
  675. int InChar()
  676. {
  677.     ULONG l;
  678.  
  679.     for (;;)
  680.     {
  681.  
  682.            CheckKey(StrOut);
  683.            l=StrOut[0];
  684.         if (l)
  685.             return(StrOut[0]);
  686.  
  687.         if (doormsg->carrier==1)
  688.         {
  689.             sprintf(txt,"%c[0;31m%cCarrier Lost.%c[37m\r\n",ESC,FF,ESC);
  690.                         Out(txt);
  691.             SendBreak('C'); 
  692.             quit=TRUE;
  693.             return(0);
  694.         }
  695.  
  696.         /* See if anything has come from out FIFO
  697.          */
  698.         check_fifo();
  699.         if (quit==TRUE)
  700.             return(0);
  701.     
  702.  
  703. /* Fix this crap later... (Don't think it's needed for Max's anyway!) */
  704.  
  705. /*
  706.         WaitTOF();
  707.         t++;
  708.         if (t>100000)
  709.         {
  710.             sprintf(txt,"%c[0;31m%cInactivity timeout.%c[37m\r\n",ESC,FF,ESC); Out(txt);
  711.             quit=TRUE;
  712.             SendBreak('C');
  713.             return(0);
  714.         }
  715. */
  716.     }
  717. }
  718.  
  719. /* Check for something from FIFO.
  720.  */
  721. void check_fifo()
  722. {
  723.     struct Message *msg;
  724.     char *ptr;
  725.  
  726.     msg=GetMsg(fifoport);
  727.  
  728.     if (msg==(struct Message *)&rmsg)
  729.     {
  730.         readpending=FALSE;
  731.         n=ReadFifo(fifoR,&ptr,0);
  732.         if (n>0)
  733.         {
  734.  
  735. /* These 2 values were 256, but changed them to this lower value to stop
  736.    the program crashing (Something to do with 80 character Max's lines?) */
  737.  
  738.             if (n>40)
  739.                 n=40;
  740.             OutLen(ptr,n);
  741.             n=ReadFifo(fifoR,&ptr,n);
  742.         }
  743.         if (n<0)
  744.             quit=TRUE;
  745.         else
  746.         {
  747.             RequestFifo(fifoR,&rmsg,FREQ_RPEND);
  748.             readpending=TRUE;
  749.         }
  750.     }
  751.     else if (msg==(struct Message *)&wmsg)
  752.         writepending=FALSE;
  753. }
  754.  
  755. /* Text output to the serial device and the terminal window.  The serial
  756.  * routines are smart enough to know whether serial I/O should take place 
  757.  * or not, so its perfectly safe to always call them like this.
  758.  */
  759. void Out(char *str)
  760. {
  761.     char temp[3000];
  762.     convert_lf(temp,str,strlen(str));
  763.         sendmessage(temp, 0);
  764. }
  765.  
  766. void OutLen(char *str, ULONG len)
  767. {
  768.         int counter, counter2, newlen, escape;
  769.     char temp[3000];
  770.  
  771.         convert_lf(temp,str,len);
  772.  
  773. /* Check for a partial escape sequence at the end of the string, and save
  774.    it for the start of the next string, if required */
  775.  
  776.         newlen=strlen(temp);
  777.         counter=newlen;
  778.         escape=FALSE;
  779.         while(counter>newlen-12 && counter>=0 && escape==FALSE)
  780.         {
  781.                 if(temp[counter]=='\033')
  782.                 {
  783.                         escape=TRUE;
  784.                 }
  785.                 counter--;
  786.         }
  787.         counter2=counter;
  788.         counter2++;
  789.         while(counter2<newlen && escape==TRUE)
  790.         {
  791.                 counter2++;
  792.                 if((temp[counter2]>='A' && temp[counter2]<='Z')
  793.                         || (temp[counter2]>='a' && temp[counter2]<='z'))
  794.                 {
  795.                         escape=FALSE;
  796.                 }
  797.         }
  798.         if(escape==TRUE)
  799.         {
  800.                 strncat(charbuf, temp, counter);
  801. /*                sendmessage("->", 0); */
  802.                 sendmessage(charbuf, 0);
  803. /*                sendmessage("<-", 0); */
  804.                 strmid(temp, charbuf, counter+1, newlen-counter+1);
  805.         }
  806.         else
  807.         {
  808.                 strcat(charbuf, temp);
  809. /*                sendmessage("=>", 0); */
  810.                 sendmessage(charbuf, 0);
  811. /*                sendmessage("<=", 0); */
  812.                 strcpy(charbuf, "");
  813.         }
  814.  
  815. }
  816.  
  817. /* Strip CR's from string, plus a few other conversions!
  818.  */
  819. void convert_lf(char *buf, char *str, LONG len)
  820. {
  821.     LONG i, ii=0;
  822.     
  823.     for (i=0; i<len; i++)
  824.     {
  825.         buf[ii]=str[i];
  826.                 if(buf[ii]=='|')
  827.                 {
  828.                         buf[ii+1]='\013';
  829.                         ii++;
  830.                 }
  831.                 if(buf[ii]=='@')
  832.                 {
  833.                         buf[ii+1]='\013';
  834.                         ii++;
  835.                 }
  836.                 if(buf[ii]=='%')
  837.                 {
  838.                         buf[ii+1]='\013';
  839.                         ii++;
  840.                 }
  841.                 if(buf[ii]=='\033')
  842.                 {
  843.                         buf[ii+1]='\033';
  844.                         ii++;
  845.                 }
  846.                 if (buf[ii]=='\r')
  847.                 {
  848.                         ii--;
  849.                 }
  850.         ii++;
  851.     }
  852.     buf[ii]='\0';
  853. }
  854.  
  855. /* Display command line usage */
  856.  
  857. void show_usage(void)
  858. {
  859.     printf("-- MAXShell v1.0 by MPS in 1995!\n");
  860.     printf("-- Based on the original TrShell by Tim Aston\n");
  861.     printf("-- M A X's BBS Remote Shell\n\n");
  862.     printf("Usage:\n\nMAXShell <startup-script> [-c] [-d] [-e] [-f] [-s<substitution char>] [-t]\n\n");
  863. }
  864.  
  865. /* Send a break.
  866.  */
  867. void SendBreak(char c)
  868. {
  869.     char buf[256];
  870.     LONG fh;
  871.  
  872.     sprintf(buf, "FIFO:%s/%c", fifoname, c);
  873.     if (fh = Open(buf, 1005))
  874.         Close(fh);
  875. }
  876.  
  877.  
  878. /* Cleanly and safely shutdown all resources.
  879.  */
  880.  
  881. void WaitMsg(struct Message *msg)
  882. {
  883.     while (msg->mn_Node.ln_Type == NT_MESSAGE)
  884.         Wait(1 << msg->mn_ReplyPort->mp_SigBit);
  885.     Forbid();
  886.     Remove(&msg->mn_Node);
  887.     Permit();
  888. }
  889.  
  890. main(int argc, char *argv[])
  891. {
  892.         /* char userstring[1000]; */
  893.         char linein[256], lineout[256], linestring[80];
  894.         long uservalue, savedflags;
  895.         int i, ii, j;
  896.     char buffer[81],line_number;
  897.     char cportname[12];    /* ReplyPort and Control Port names */
  898.         char infilename[80]="DOORS:MAXSHELL/";
  899.  
  900.     /* Pull out the line number from the argv field to find where we are */
  901.     
  902.     line_number=argv[argc-1][0];
  903.  
  904.     mytask=(struct Task *)FindTask('\0');
  905.     mytask->tc_Node.ln_Name = "DoorExample";
  906.  
  907.     /* Create the Reply port, with the name based on the number... */
  908.     
  909.     sprintf(buffer,"DoorReply%c",line_number);
  910.     replyport=(struct MsgPort *)CreatePort(buffer,0L);
  911.     
  912.     doormsg=(struct DoorMsg *)AllocMem((long)sizeof(*doormsg),MEMF_PUBLIC);
  913.     
  914.     if(doormsg==0)
  915.     {
  916.         puts("Couldn't allocate DoorMsg!");
  917.                 show_usage();
  918.         return;
  919.     }
  920.     
  921.     doormsg->Door_Msg.mn_Node.ln_Type = NT_MESSAGE;
  922.     doormsg->Door_Msg.mn_ReplyPort = replyport;
  923.     doormsg->Door_Msg.mn_Length = (UWORD)sizeof(*doormsg);
  924.     
  925.     /* Locate the correct DoorControl port based on the line number */
  926.     
  927.     sprintf(cportname,"DoorControl%c",line_number);
  928.        MyPort=(struct MsgPort *)FindPort(cportname);
  929.        if(MyPort==0L) 
  930.     {
  931.         puts("DoorControl port not located!");
  932.         FreeMem(doormsg,(long)sizeof(*doormsg));
  933.                 show_usage();
  934.         return;
  935.     }
  936.  
  937.     /* Parse command line switch arguments.
  938.      */
  939.  
  940.     for (i=1; i<argc; i++)
  941.     {
  942.         if (argv[i][0]=='-')
  943.         {
  944.             switch (argv[i][1])
  945.             {
  946.                 case 'c':
  947.                 case 'C':
  948.                     filterc=TRUE;
  949.                     break;
  950.                 case 'F':
  951.                 case 'f':
  952.                     filterf=TRUE;
  953.                     break;
  954.                 case 'D':
  955.                 case 'd':
  956.                     filterd=TRUE;
  957.                     break;
  958.                 case 'E':
  959.                 case 'e':
  960.                     filtere=TRUE;
  961.                     break;
  962.                                 case 's':
  963.                                 case 'S':
  964.                                         newchar=argv[i][2];
  965.                                         break;
  966.                                 case 'T':
  967.                                 case 't':
  968.                                         lesstime=TRUE;
  969.             }
  970.                 }
  971.     }
  972.  
  973. /* Open a CLI redirected to FIFO: based on an individual filename
  974.      generated from the system time (Hope it's not too long!) */
  975.  
  976. /* The same filename is also used for the names of the two FIFO's, opened
  977.    later */
  978.    
  979. timeval=time(timeptr);
  980. sprintf(fifoname, "%d_%c", timeval, line_number);
  981. strcat(commandline, fifoname);
  982. strcat(commandline, "/rwkecs");
  983. if(argc>2)
  984. {
  985.         /* Generate a new Shell-Startup script with proper autoinserts
  986.            (Name is based on the same FIFO: filename used above) */
  987.         strcat(infilename, argv[1]);
  988.         ifp=fopen(infilename, "r");
  989.         if(ifp==NULL)
  990.         {
  991.                 sendmessage("Can't open given startup script - Opening a standard shell.\r\n", 0);
  992.         }
  993.         else
  994.         {
  995.                 sprintf(newfile,"RAM:%s", fifoname);
  996.                 ofp=fopen(newfile, "w");
  997.                 while(fgets(linein, 256, ifp)!=NULL)
  998.                 {
  999.                    ii=0;
  1000.                    for(i=0; i<strlen(linein);i++)
  1001.                    {
  1002.                       lineout[ii]=linein[i];
  1003.                       if(lineout[ii]=='%')
  1004.                       {
  1005.                          i++;
  1006.                          GetAutoInsert(linein[i], linestring);
  1007.                          for(j=0; j<strlen(linestring); j++)
  1008.                          {
  1009.                             lineout[ii]=linestring[j];
  1010.                             ii++;
  1011.                          }
  1012.                          ii--;
  1013.                       }
  1014.                       ii++;
  1015.                    }
  1016.                    lineout[ii]='\0';
  1017.                    fprintf(ofp, "%s", lineout);
  1018.                 }
  1019.                 fclose(ifp);
  1020.                 fclose(ofp);
  1021.         /* ... and add the right stuff to the command line. */
  1022.                 strcat(commandline," FROM ");
  1023.                 strcat(commandline, newfile); /* Converted Shell-Startup script */
  1024.         }
  1025. }
  1026. system(commandline);
  1027.  
  1028. /*
  1029.         sendmessage(commandline,1);
  1030.     sendmessage("\r\nHi there! Welcome to the test version of MAXShell\r\n",1);
  1031.  
  1032.         uservalue=getuserint(1);
  1033.         sprintf(userstring, "The user's flags value: %ld\n", uservalue);
  1034.         sendmessage(userstring, 0);
  1035.  
  1036.     hotkey("Press any key to (most likely) crash the computer...",buffer);    
  1037. */
  1038.  
  1039. /* Set user's PAUSE flag to OFF, so the annoying 'Press Return' doesn't appear
  1040.    all the time in scrolling text doors such as Hack & Slash (And the standard
  1041.    shell). The user's previous flag value is saved for restoration before
  1042.    returning back to the BBS */
  1043.  
  1044. uservalue=getuserint(108);
  1045. savedflags=uservalue;
  1046. uservalue&=0xffffff7fL; /* Turn bit 7 (Pause) of the user's flags OFF */
  1047. changeuserint(13, uservalue);
  1048.  
  1049.     /* Open fifo.library.
  1050.      */
  1051.         FifoBase=OpenLibrary("fifo.library",0L);
  1052.         if(!FifoBase)
  1053.     {
  1054.         printf("ERROR: Couldn't open fifo.library\n");
  1055.  
  1056. /* Temporary: I'll have to change this ... */
  1057.  
  1058.         exit(10);
  1059.                 CloseLibrary(FifoBase);
  1060.     }
  1061.  
  1062.     setup_fifo();
  1063.     shell_loop();
  1064.  
  1065.     close_all();
  1066.  
  1067. /* Delete temporary shell-startup file... */
  1068.  
  1069.         strcpy(linein, "c:delete ");
  1070.         strcat(linein, newfile);
  1071.         system(linein);
  1072.  
  1073. /* Restore user's previous PAUSE flag setting */
  1074.  
  1075.         changeuserint(13, savedflags);
  1076.  
  1077. /* Close down the door... */
  1078.  
  1079.         end();
  1080.  
  1081. }
  1082.  
  1083. void close_all(void)
  1084. {
  1085.     if (readpending)
  1086.     {
  1087.         RequestFifo(fifoR, &rmsg, FREQ_ABORT);
  1088.         WaitMsg(&rmsg);
  1089.     }
  1090.     if (writepending)
  1091.     {
  1092.         RequestFifo(fifoW, &wmsg, FREQ_ABORT);
  1093.         WaitMsg(&wmsg);
  1094.     }
  1095.     if (fifoR) CloseFifo(fifoR, FIFOF_EOF);
  1096.     if (fifoW) CloseFifo(fifoW, FIFOF_EOF);
  1097.     if (fifoport) DeletePort(fifoport);
  1098.         if (FifoBase) CloseLibrary(FifoBase);
  1099. }
  1100.